#include"stdlib.h"
#include"stdio.h"
#include <pthread.h>
#include <papi.h>
#define np 31
#define H ((mhandle*) handle)
typedef struct nb{
unsigned int nc;
unsigned int* index;
double* data;
} nb;
typedef struct mhandle{
unsigned int rank;
unsigned int row;
unsigned int col;
double* v;
nb* m;
double* rt;
} mhandle;
unsigned int next_pos;
pthread_spinlock_t lo;
void* mkernel(void* handle){
	unsigned int i,i2,j,bd;
	i=0;
	bd=(319+(H->row))/320;
	//printf("%d %d\n",H->rank,next_pos);
while(i<H->row){
pthread_spin_lock(&lo);
//printf("lock %d %d\n",H->rank,next_pos);
i=next_pos;
next_pos+=bd;
pthread_spin_unlock(&lo);
//printf("%d %d\n",H->rank,i);
i2=i+bd;
	while((i<H->row)&&(i<i2)){
		//if((i%np)==(H->rank)){
			//if((H->m)[i].nc!=0){
				for(j=0;j<(H->m)[i].nc;j++){
					(H->rt)[i]+=(H->m)[i].data[j]*(H->v)[(H->m)[i].index[j]];
				}
			//}
		//}
		i++;
	}
}
	printf("T: %d  %ld\n",H->rank,PAPI_get_real_usec());
	fflush(stdout);
	return NULL;
}
int main(int argc,char* argv[]){
  unsigned long chkflg = PAPI_VER_CURRENT;
	pthread_spin_init(&lo, 0);
	unsigned int row, trow, col, num, i, j, k, x, y, dummy;
  unsigned long start, end;
	double temp;
	double** mt;
	double* rt;
        double* v;
        nb* sm;
        long ix;
	char du[1024];
	unsigned int rz;
	mhandle tt[np];
	pthread_t threadid[np];
	//pthread_mutex_init(&lock, NULL);
	next_pos=0;
	FILE* fin=fopen(argv[1],"r");
	fgets(du, 1024, fin);
    	fscanf(fin,"%d", &row);
	fscanf(fin,"%d", &col);
	fscanf(fin,"%d", &num);
	mt = (double**)calloc(row,sizeof(double*));
	rt = (double*)calloc(row,sizeof(double));
	for(i=0;i< row;i++){
		mt[i] = (double*)calloc(col,sizeof(double));
	}

/**************************************************
 *               Init PAPI
**************************************************/
  PAPI_library_init(chkflg);
  if (chkflg != PAPI_VER_CURRENT) {
    printf("Error PAPI Library out of date\n");
    exit(1);
  }

    	for(i=0;i< num;i++){
      		fscanf(fin,"%d", &x);
		fscanf(fin,"%d", &y);
		fscanf(fin,"%lf", &temp);
		mt[x-1][y-1]=temp;
    	}
    	fclose(fin);
	fin=fopen(argv[2],"r");
	fgets(du, 1024, fin);
    	fscanf(fin,"%d", &dummy);
	fscanf(fin,"%d", &dummy);
	fscanf(fin,"%d", &dummy);
	v = (double*)calloc(col,sizeof(double));
    	for(i=0;i< dummy;i++){
      		fscanf(fin,"%d", &x);
		fscanf(fin,"%d", &y);
		fscanf(fin,"%lf", &temp);
		v[x-1]=temp;
    	}
    	fclose(fin);
	trow=0;
	for(i=0;i<row;i++){
		rz=0;
		for(j=0;j<col;j++){
			if(mt[i][j]!=0){
				rz=1;
			}
		}
		if(rz==1){
			trow++;
		}
	}
	sm= (nb*)calloc(trow,sizeof(nb));
	for(ix=trow-1;ix>=0;ix--){
		(sm+ix)->nc=0;
		for(j=0;j<col;j++){
			if((mt[ix][j]!=0)&&(v[j]!=0)){
				(sm+ix)->nc++;
			}
		}
		(sm+ix)->index=(unsigned int*)malloc(((sm+ix)->nc)*sizeof(unsigned int));
		(sm+ix)->data=(double*)malloc(((sm+ix)->nc)*sizeof(double));
		k=0;
		for(j=0;j<col;j++){
			if((mt[ix][j]!=0)&&(v[j]!=0)){
				((sm+ix)->index)[k]=j;
				((sm+ix)->data)[k++]=mt[ix][j];
			}
		}
	}
	for(i=0;i<np;i++){
		tt[i].row=trow;
		tt[i].col=col;
		tt[i].v=v;
		tt[i].m=sm;
		tt[i].rank=i;
		tt[i].rt=rt;
	}

  start = PAPI_get_real_usec();
  for(i=0; i<np; i++){
		pthread_create(&threadid[i], NULL, mkernel, (void*)&tt[i]);
  }

	for(i=0; i<np; i++){
    		pthread_join(threadid[i], NULL);
  	}	
  end = PAPI_get_real_usec();
	for(i=0;i<row;i++){
		printf("%lf\n",rt[i]);
	}
  printf("time: %ld", end-start);
	return 0;
}
